﻿#region

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using Pob.CustomEventArgs;
using Pob.GameObjects;

#endregion

namespace Pob
{
    public delegate void MenuControlEvent(object sender, MenuControlEventArgs args);

    public class MenuControl
    {
        #region Constants

        private const float MaxBuffer = 2.0f;

        #endregion

        #region Fields

        private readonly List<MenuItem> _allMenuItems;

        private readonly List<string> _allowedChars = new List<string>
            {
                "a", 
                "b", 
                "c", 
                "d", 
                "e", 
                "f", 
                "g", 
                "h", 
                "i", 
                "j", 
                "k", 
                "l", 
                "m", 
                "n", 
                "o", 
                "p", 
                "q", 
                "r", 
                "s", 
                "t", 
                "u", 
                "v", 
                "w", 
                "x", 
                "y", 
                "z", 
                "1", 
                "2", 
                "3", 
                "4", 
                "5", 
                "6", 
                "7", 
                "8", 
                "9"
            };

        private readonly List<Keys> _allowedNumbers = new List<Keys>
            {
                Keys.D0, 
                Keys.D1, 
                Keys.D2, 
                Keys.D3, 
                Keys.D4, 
                Keys.D5, 
                Keys.D6, 
                Keys.D7, 
                Keys.D8, 
                Keys.D9, 
                Keys.NumPad0, 
                Keys.NumPad1, 
                Keys.NumPad2, 
                Keys.NumPad3, 
                Keys.NumPad4, 
                Keys.NumPad5, 
                Keys.NumPad6, 
                Keys.NumPad7, 
                Keys.NumPad8, 
                Keys.NumPad9
            };

        private readonly int _lastPos;

        private float _buffer;

        private int _currPos;

        private bool _firstExtInput;

        private KeyboardState _kbState;

        private bool _keyPressed;

        private Keys[] _oldKeySet;

        private int _oldPos;

        private Keys[] _pressedKeys;

        #endregion

        #region Constructors and Destructors

        public MenuControl(List<MenuItem> menuItemList)
        {
            _allMenuItems = menuItemList;
            _currPos = 0;
            _oldPos = 0;
            _firstExtInput = true;
            _buffer = MaxBuffer;

            // _lastPos ist ein bei Null beginnender Index, Count Methode gibt Anzahl beginnend ab 1 zurück
            _lastPos = menuItemList.Count - 1;
            _kbState = new KeyboardState();
        }

        #endregion

        #region Public Events

        public event MenuControlEvent ItemPicked;

        #endregion

        #region Public Methods and Operators

        public virtual void Update(GameTime gameTime)
        {
            // MenuItem bei dem die Extension selected ist holen
            var extItem = _allMenuItems.FirstOrDefault(x => x.ItemExtension != null && x.ItemExtension.Selected);

            _kbState = Keyboard.GetState();
            _pressedKeys = _kbState.GetPressedKeys();

            if (extItem != null)
            {
                if (extItem.ExtendedMode == MenuItemExtendedMode.String)
                {
                    EnterStringMode(extItem);
                }

                if (extItem.ExtendedMode == MenuItemExtendedMode.Key)
                {
                    EnterKeyMode(extItem);
                }
            }
            else
            {
                if (_pressedKeys.Length == 0)
                {
                    _keyPressed = false;
                    _buffer = MaxBuffer;
                }
                else if (!_keyPressed)
                {
                    _oldPos = _currPos;

                    if (_kbState.IsKeyDown(Keys.Up))
                    {
                        _keyPressed = true;

                        _currPos = _currPos == 0 ? _lastPos : _currPos - 1;

                        SwitchSelectedMenuItem(_allMenuItems.ElementAt(_oldPos), _allMenuItems.ElementAt(_currPos));
                    }
                    else if (_kbState.IsKeyDown(Keys.Down))
                    {
                        _keyPressed = true;

                        _currPos = _currPos == _lastPos ? 0 : _currPos + 1;

                        SwitchSelectedMenuItem(_allMenuItems.ElementAt(_oldPos), _allMenuItems.ElementAt(_currPos));
                    }
                    else if (_kbState.IsKeyDown(Keys.Enter))
                    {
                        _keyPressed = true;
                        _firstExtInput = true;

                        OnItemPicked(_allMenuItems.ElementAt(_currPos), _pressedKeys);
                    }
                }
            }

            _oldKeySet = _pressedKeys;
        }

        #endregion

        #region Methods

        private void EnterKeyMode(MenuItem extItem)
        {
            if (_firstExtInput)
            {
                _firstExtInput = _kbState.GetPressedKeys().Length > 0;
            }
            else
            {
                Keys key = _kbState.GetPressedKeys().FirstOrDefault();
                if (key != Keys.Escape && key != Keys.Enter && key != Keys.None)
                {
                    extItem.ItemExtension.Text = key.ToString();
                    _firstExtInput = true;

                    OnItemPicked(_allMenuItems.ElementAt(_currPos), _pressedKeys);
                }

                if (key == Keys.Enter || key == Keys.Escape)
                {
                    _keyPressed = true;
                    _firstExtInput = true;

                    OnItemPicked(_allMenuItems.ElementAt(_currPos), _pressedKeys);
                }
            }
        }

        private void EnterStringMode(MenuItem extItem)
        {
            if (_firstExtInput)
            {
                _firstExtInput = _kbState.GetPressedKeys().Length > 0;
            }
            else
            {
                if (_pressedKeys.Length == 0)
                {
                    _buffer = MaxBuffer;
                }

                if (_kbState.IsKeyDown(Keys.Back) && extItem.ItemExtension.Text.Length > 0)
                {
                    if (_buffer == MaxBuffer || _buffer <= 0)
                    {
                        extItem.ItemExtension.Text = extItem.ItemExtension.Text.Remove(extItem.ItemExtension.Text.Length - 1);
                    }

                    if (_buffer > 0)
                    {
                        _buffer -= 0.1f;
                    }
                }

                if (_kbState.IsKeyDown(Keys.Enter) || _kbState.IsKeyDown(Keys.Escape))
                {
                    _keyPressed = true;
                    _firstExtInput = true;

                    OnItemPicked(_allMenuItems.ElementAt(_currPos), _pressedKeys);
                }

                foreach (Keys key in _pressedKeys)
                {
                    if (!_oldKeySet.Contains(key))
                    {
                        var ksplit = key.ToString().Split(new[]
                            {
                                '.'
                            });
                        if (ksplit.Length > 0 && _allowedChars.Contains(ksplit[0].ToLower()) && extItem.ItemExtension.Text.Length < 10)
                        {
                            extItem.ItemExtension.Text += ksplit[0].ToLower();
                        }

                        if (_allowedNumbers.Contains(key) && extItem.ItemExtension.Text.Length < 10)
                        {
                            var regEx = Regex.Match(key.ToString(), "[0-9]");
                            extItem.ItemExtension.Text += regEx.Value;
                        }
                    }
                }
            }
        }

        private void OnItemPicked(MenuItem pickedItem, Keys[] keys)
        {
            var me = new MenuControlEventArgs(pickedItem, keys);

            if (ItemPicked != null)
            {
                ItemPicked(this, me);
            }

            pickedItem.OnMenuItemClicked(this, null);
        }

        private void SwitchSelectedMenuItem(MenuItem oldItem, MenuItem newItem)
        {
            oldItem.Item.Selected = false;
            newItem.Item.Selected = true;
        }

        #endregion
    }
}